/***********************************************************************
Compile       : gcc -O3 -o design main.c design.c utils.c
Usage         : ./design mode mode1 mode2 irflag bdflag dgflag pnflag N L inputfile 
                (./design 0 0 0 0 0 0 0 11 12 Budding.txt)
mode          : 0 normal ; 1 cycled ; 2 triggled cycled
mode1         : 0 disallow self-activation ; 1 allow self_activation
mode2         : 0 no Restrictions ; 1 Restriction I ; 2 Restriction II; 3 Restriction I and II
irflag        : 1 irreducible solution only
bdflag        : 1 breakdown the designability by number of the links
dgflag	      : 1/2 breakdown the designability by number of the degrees(r<->g is counted for 2)
pnflag        : 1 print the solutions
N             : number of the nodes
L             : number of the steps        
Output        : activity min_link designability1 designability2
activity      : number of 1 in the process
min_link      : minimum links of the qualified network
designability1: the minimum designability for one node
designability2: total designability
***********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "design.h"

void print_help ()
{
	printf ("Usage         : ./design mode mode1 mode2 irflag bdflag dgflag pnflag N L inputfile\n");
	printf ("                (./design 0 0 0 0 0 0 0 11 12 Budding.txt)\n");
	printf ("mode          : 0 normal ; 1 cycled ; 2 triggled cycled\n");
	printf ("mode1         : 0 disallow self-activation ; 1 allow self_activation\n");
	printf ("mode2         : 0 no Restrictions ; 1 Restriction I ; 2 Restriction II; 3 Restriction I and II\n");
	printf ("irflag        : 1 irreducible solution only\n");
	printf ("bdflag        : 1 breakdown the designability by number of the links\n");
	printf ("dgflag        : 1/2 breakdown the designability by number of the degrees(r<->g is counted for 2)\n");
	printf ("pnflag        : 1 print the solutions\n");
	printf ("N             : number of the nodes\n");
	printf ("L             : number of the steps\n\n");
	printf ("Output        : activity min_link designability1 designability2 fix_edges free_edges\n");
	printf ("activity      : number of 1 in the process\n");
	printf ("min_link      : minimum links of the qualified network\n");
	printf ("designability1: the minimum designability for one node\n");
	printf ("designability2: total designability\n");
	printf ("fix_edges     : total number of fixed edges\n");
	printf ("free_edges    : total number of totally free edges\n");
}

void init_design (struct designability *design, int argc, char *argv[])
{
	int N, L, i;

	design->mode = atoi (argv[1]);
	design->mode1 = atoi (argv[2]);
	design->mode2 = atoi (argv[3]);
	design->irflag = atoi (argv[4]);
	design->bdflag = atoi (argv[5]);
	design->dgflag = atoi (argv[6]);
	design->pnflag = atoi (argv[7]);
	design->svflag = 1;
	design->N = atoi (argv[8]);
	design->L = atoi (argv[9]);

	design->N += design->mode1;
	N = design->N;
	L = design->L;

	/* the degree of irreducible solution is zero */
	if (design->irflag)
		design->dgflag = 0;

	design->pathway = calloc (sizeof (int), N * L);
	design->NS2 = calloc (sizeof (int), N);
	design->min_link = calloc (sizeof (int), N);
	design->links_dist = calloc (sizeof (int), N * (N + 1));
	design->Links_dist = calloc (sizeof (double), N * N + 1);
	design->degree_dist = calloc (sizeof (int), N * (2 * N + 1));
	design->Degree_dist = calloc (sizeof (double), 2 * N * N + 1);
	design->solution = calloc (sizeof (struct solution), N);

	for (i = 0; i < N; i++)
	{
		init_solution (&(design->solution[i]));
	}
}

void free_design (struct designability *design)
{
	int i;

	free (design->pathway);
	free (design->NS2);
	free (design->min_link);
	free (design->links_dist);
	free (design->Links_dist);
	free (design->degree_dist);
	free (design->Degree_dist);
	free (design->solution);

	for (i = 0; i < design->N; i++)
	{
		free_solution (&(design->solution[i]));
	}
}

void print_solution (struct designability *design)
{
	int i, j, k, N;

	N = design->N;
	if (design->svflag && design->pnflag)
	{
		for (i = design->mode1; i < N; i++)
		{
			printf ("Total Number of Soultion for Node %2d : %d\n", i - design->mode1, design->NS2[i]);
			for (j = 0; j < design->solution[i].curr; j++)
			{
				//printf ("Node %2d :", i - design->mode1);
				for (k = design->mode1; k < N; k++)
				{
					if (design->mode1 == 1 && k == i && design->solution[i].edge[j * N] == 1)
						printf ("g ");
					else if (design->solution[i].edge[j * N + k] == 0)
						printf ("n ");
					else if (design->solution[i].edge[j * N + k] == 1)
						printf ("g ");
					else if (design->solution[i].edge[j * N + k] == -1)
						printf ("r ");
				}
				printf ("\n");
			}
		}
	}
}

void print_pathway (struct designability *design)
{
	int i, j;

	printf ("c %3d %3d %5d %lg %3d %3d\n", design->activity, design->min_links, design->NS2_min, design->NS, design->fix_edges, design->free_edges);

	for (i = 0; i < design->L; i++)
	{
		for (j = design->mode1; j < design->N; j++)
		{
			printf ("%d ", design->pathway[i * design->N + j]);
		}
		printf ("\n");
	}
}

void print_bddist (struct designability *design)
{
	int i, N;

	N = design->N;

	if (design->bdflag)
	{
		for (i = 0; i <= N * N; i++)
		{
			if (design->Links_dist[i] > 0.1)
			{
				printf ("c Number of Links : %3d\tNumber of Solution : %lg\n", i, design->Links_dist[i]);
			}
		}
	}
}

void print_dgdist (struct designability *design)
{
	int i, j, N;

	N = design->N;

	if (design->dgflag)
	{
		for (i = 0; i <= 2 * N * N; i++)
		{
			if (design->Degree_dist[i] > 0.1)
			{
				printf ("c Number of Degrees: %3d\tNumber of Solution : %lg\n", i, design->Degree_dist[i]);
			}
		}
	}
}

int main (int argc, char *argv[])
{
	struct designability design;

	if (argc == 1)
	{
		print_help ();
		exit (0);
	}

	init_design (&design, argc, argv);

	FILE *fp;
	char buf[256];
	int i, j, N, L;

	N = design.N;
	L = design.L;

	fp = fopen (argv[10], "r");

	while (fgets (buf, 256, fp))
	{
		design.activity = 0;
		for (i = 0; i < L; i++)
		{
			for (j = 0; j < N; j++)
			{
				if (design.mode1 == 1 && j == 0)
				{
					design.pathway[i * N + j] = 1;
					continue;
				}
				fscanf (fp, "%d", &(design.pathway[i * N + j]));
				if (i <= L - 3 || (i == L - 2 && design.mode != 2))
					design.activity += design.pathway[i * N + j];
			}
			fgets (buf, 256, fp);
		}

		if (design.mode == 2)
			design.activity --;

		/* Get the number of solution using enumerating algorithm */
		if (calc_design (&design) == 0)
			continue;

		print_pathway (&design);
		print_solution (&design);
		print_bddist (&design);
		print_dgdist (&design);
	}

	fclose (fp);

	free_design (&design);

	exit (0);
}
